import java.util.concurrent.locks.ReentrantLock;

/**
 * @description: 可重入锁，也叫做递归锁，指的是同一线程 外层函数获得锁之后 ，内层递归函数仍然有获取该锁的代码，但不受影响。
 * ReentrantLock 和synchronized 都是 可重入锁
 * @author: zys
 * @create: 2020-10-12 15:23
 **/
public class TestLock {

    /**
     * synchronized 的方式
     */
    static class synchronizedTest implements Runnable {
        public synchronized void get() {
            System.out.println(Thread.currentThread().getId());
            set();
        }

        public synchronized void set() {
            System.out.println(Thread.currentThread().getId());
        }

        @Override
        public void run() {
            get();
        }
    }

    /**
     * ReentrantLock 的方式
     */
    static class ReentrantLockTest implements Runnable {
        ReentrantLock lock = new ReentrantLock();

        public void get() {
            lock.lock();
            System.out.println(Thread.currentThread().getId());
            set();
            lock.unlock();
        }

        public void set() {
            lock.lock();
            System.out.println(Thread.currentThread().getId());
            lock.unlock();
        }

        @Override
        public void run() {
            get();
        }

    }

    /**
     * 同一个线程id被连续输出两次说明该锁是可重入的
     * 对于自旋锁来说， 有同一线程两调用lock() ，会导致第二次调用lock位置进行自旋，产生了死锁说明这个锁并不是可重入的。
     * 可重入锁的一个优点是可一定程度避免死锁。
     */
    public static void main(String[] args) {
        //两种不同方式的实现
        synchronizedTest st = new synchronizedTest();
        new Thread(st).start();
        new Thread(st).start();
        new Thread(st).start();

        ReentrantLockTest rt = new ReentrantLockTest();
        new Thread(rt).start();
        new Thread(rt).start();
        new Thread(rt).start();
    }

}
